package edu.del.springbootredisbusinesspractice.service.impl;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import edu.del.springbootredisbusinesspractice.service.ProductStockService;
import edu.del.springbootredisbusinesspractice.service.repository.ProductStockRepository;
import edu.del.springbootredisbusinesspractice.utils.cachekey.CacheConstants;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@Order(2)
public class CacheService {

    @Autowired
    private ProductStockRepository stockRepository;

    private static Cache<String, Long> stockCache;

    @PostConstruct
    public void init() {
        stockCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(1000)
                .build();
        log.info("【本地缓存初始化】Caffeine Stock Cache 已启动");
    }

    /**
     * 获取商品库存（使用本地缓存）
     * @param productId 商品ID
     * @return 商品库存
     */
    public Long getStockWithLocalCache(int productId) {
        String cacheKey = String.format(CacheConstants.STOCK_KEY_PREFIX, productId);

        // 1. 先查本地缓存
        Long cachedStock = stockCache.getIfPresent(cacheKey);
        if (cachedStock != null) {
            log.debug("【本地缓存命中】商品ID: {}，库存: {}", productId, cachedStock);
            return cachedStock;
        }

        // 2. 本地缓存未命中，从 Redis 加载（通过 ProductStockRepository，不再依赖 ProductStockService）
        Long redisStock = stockRepository.getStockFromRedis(productId);
        if (redisStock == null) {
            log.error("【加载商品库存失败】商品ID: {}，Redis中未找到库存", productId);
            throw new RuntimeException("获取商品库存失败，请稍后再试");
        }

        stockCache.put(cacheKey, redisStock);
        log.info("【本地缓存未命中，从Redis加载】商品ID: {}, 库存: {}", productId, redisStock);
        return redisStock;
    }

    /**
     * 更新本地缓存
     * @param productId 商品ID
     * @param newStock 新库存
     */
    public void updateStockInLocalCache(int productId, Long newStock) {
        if (newStock != null) {
            String cacheKey = String.format(CacheConstants.STOCK_KEY_PREFIX, productId);
            stockCache.put(cacheKey, newStock);
            log.debug("【本地缓存更新】商品ID: {}，新库存: {}", productId, newStock);
        }
    }

    /**
     * 清除本地缓存
     * @param productId 商品ID
     */
    public void evictStockFromLocalCache(int productId) {
        String cacheKey = String.format(CacheConstants.STOCK_KEY_PREFIX, productId);
        stockCache.invalidate(cacheKey);
        log.debug("【本地缓存清除】商品ID: {}", productId);
    }

    /**
     * 获取本地缓存
     * @return 本地缓存
     */
    public Cache<String, Long> getStockCache() {
        return stockCache;
    }

    /**
     * 检查本地缓存中是否有库存
     * @param productId 商品ID
     */
    public void checkStockInLocalCacheOrThrow(int productId) {
        String cacheKey = String.format(CacheConstants.STOCK_KEY_PREFIX, productId);
        Long stock = stockCache.getIfPresent(cacheKey);
        if (stock == null || stock <= 0) {
            log.warn("【本地缓存拦截】商品ID: {} 库存不存在或已售罄，直接拦截请求", productId);
            throw new RuntimeException("商品库存不足或不存在");
        }
        log.debug("【本地缓存命中】商品ID: {}，库存充足: {}", productId, stock);
    }

}
